#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/***待排序的 char 类型对象的相邻两个元素进行比较***/
/*
* e1: 相邻的前一个元素的地址
* e2: 相邻的后一个元素的地址
* return: >0 ------ e1指向的内容大于e2指向的内容
*		  =0 ------ e1指向的内容等于e2指向的内容
*         <0 ------ e1指向的内容小于e2指向的内容
*/
int cmp_by_ch(const void* e1, const void* e2)
{
	return *(const char*)e1 - *(const char*)e2;
}


/***待排序的 int 类型对象的相邻两个元素进行比较***/
/*
* e1: 相邻的前一个元素的地址
* e2: 相邻的后一个元素的地址
* return: >0 ------ e1指向的内容大于e2指向的内容
*		  =0 ------ e1指向的内容等于e2指向的内容
*         <0 ------ e1指向的内容小于e2指向的内容
*/
int cmp_by_int(const void* e1, const void* e2)
{
	return *(const int*)e1 - *(const int*)e2;
}


/***待排序的 字符串 类型对象的相邻两个元素进行比较***/
/*
* e1: 相邻的前一个元素的地址
* e2: 相邻的后一个元素的地址
* return: >0 ------ e1指向的内容大于e2指向的内容
*		  =0 ------ e1指向的内容等于e2指向的内容
*         <0 ------ e1指向的内容小于e2指向的内容
*/
int cmp_by_str(const void* e1, const void* e2)
{
	return strcmp(*(const char**)e1, *(const char**)e2);
}


/***待排序的 结构体 类型对象的相邻两个元素进行比较***/
/*
* e1: 相邻的前一个元素的地址
* e2: 相邻的后一个元素的地址
* return: >0 ------ e1指向的内容大于e2指向的内容
*		  =0 ------ e1指向的内容等于e2指向的内容
*         <0 ------ e1指向的内容小于e2指向的内容
*/
typedef struct
{
	char name[20];
	int age;
}Stu;

/***按照 字符串 类型排序，如名字***/
int cmp_by_stu_name(const void* e1, const void* e2)
{
	return strcmp(((const Stu*)e1)->name, ((const Stu*)e2)->name);
}

/***按照 int 类型排序，如年龄***/
int cmp_by_stu_age(const void* e1, const void* e2)
{
	return ((const Stu*)e1)->age - ((const Stu*)e2)->age;
}


/***待排序的对象的相邻两个元素的内容进行交换***/
/*
* buf1: 相邻的前一个元素的地址
* buf2: 相邻的后一个元素的地址
* size: 该对象每一个元素的大小，单位为字节
*/
void swap(char* buf1, char* buf2, int size)
{
	int i = 0;

	for (i = 0; i < size; i++)
	{
		*buf1 = *buf1 + *buf2;
		*buf2 = *buf1 - *buf2;
		*buf1 = *buf1 - *buf2;
		
		buf1++;
		buf2++;
	}
}


/***模拟快速排序功能实现冒泡排序***/
/*
* base: 待排序的对象中第一个元素的地址
*  num: 待排序的对象中所有元素的数量
* size: 待排序的对象中一个元素的大小，单位为字节
* compar: 函数指针，指向待排序的对象的两个元素比较函数
*/
void bsort(void* base, int num, int size, int (*compar)(const void*, const void*))
{
	int i = 0;
	int j = 0;

	for (i = 0; i < num - 1; i++)
	{
		int flag = 0;
		for (j = 0; j < num - 1 - i; j++)
		{
			if (compar((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
			{
				//进行内容交换
				swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
				flag = 1;
			}			
		}

		//如果经过一轮比较后flag还是等于0，说明此时序列已经排序完成了
		if (!flag)
		{
			break;
		}
	}
}


/***打印 char 类型序列的数据***/
void print_ch(char* base, int num)
{
	int i = 0;
	for (i = 0; i < num; i++)
	{
		printf("%c ", *(base + i));
	}
	printf("\n");
}


/***打印 int 类型序列的数据***/
void print_int(int* base, int num)
{
	int i = 0;
	for (i = 0; i < num; i++)
	{
		printf("%d ", *(base + i));
	}
	printf("\n");
}


/***打印 字符串 类型序列的数据***/
void print_str(char* base[], int num)
{
	int i = 0;
	for (i = 0; i < num; i++)
	{
		printf("%s\n", *(base + i));
	}
	printf("\n");
}


/***打印 结构体 类型序列的数据***/
void print_stu(Stu* base, int num)
{
	int i = 0;
	for (i = 0; i < num; i++)
	{
		printf("%s %d\n", (base + i)->name, (base + i)->age);
	}
}



/*** char 类型序列数据排序测试***/
void test1(void)
{
	char arr[] = {'1', '8', 'a', 'g', '5', 'A', 'c', 'C', 'L', 'l', 'k', 'O'};
	int num = sizeof(arr) / sizeof(arr[0]);
	int size = sizeof(arr[0]);

	printf("char 类型序列排序测试>>>\n");
	printf("初始序列>>> ");
	print_ch(arr, num);

	bsort(arr, num, size, cmp_by_ch);
	print_ch(arr, num);
}


/*** int 类型序列数据排序测试***/
void test2(void)
{
	int arr[] = { '1', '8', 'a', 'g', '5', 'A', 'c', 'C', 'L', 'l', 'k', 'O' };
	int num = sizeof(arr) / sizeof(arr[0]);
	int size = sizeof(arr[0]);

	printf("\nint 类型序列排序测试>>>\n");
	printf("初始序列>>> ");
	print_int(arr, num);

	bsort(arr, num, size, cmp_by_int);
	print_int(arr, num);
}


/*** 字符串 类型序列数据排序测试***/
void test3(void)
{
	char* a = "lin";
	char* b = "chen";
	char* c = "hope";
	char* d = "heiha";

	char* arr[] = { a, b, c, d };

	int num = sizeof(arr)/ sizeof(arr[0]);
	int size = sizeof(arr[0]);

	printf("\n字符串 类型序列排序测试>>>\n");
	printf("初始序列>>>\n");
	print_str(arr, num);

	bsort(arr, num, size, cmp_by_str);
	print_str(arr, num);
}


/*** 结构体 类型序列数据排序测试***/
void test4(void)
{
	Stu std[] = { {"lin", 20}, {"chen", 20}, {"kobe", 24}, {"xiao", 22} };
	int num = sizeof(std) / sizeof(std[0]);
	int size = sizeof(std[0]);

	printf("\n结构体 类型序列排序测试>>>\n");
	printf("初始序列>>>\n");
	print_stu(std, num);

	//按照 字符串 类型排序，如名字
	printf("\n按照 名字 排序>>>\n");
	bsort(std, num, size, cmp_by_stu_name);
	print_stu(std, num);

	//按照 int 类型排序，如年龄
	printf("\n按照 年龄 排序>>>\n");
	bsort(std, num, size, cmp_by_stu_age);
	print_stu(std, num);
	
}


/***框架***/
/*
* 实现冒泡排序bsort( ， ， ，int (*compar)(const void *, const void *))；
* bsort()里通过函数指针compar调用它所指向的比较函数（比较函数对于不同类型的待排序对象而不同）；
* 通过比较函数的返回值判断是否需要调用交换函数swap()。
*/
/***实现功能***/
/*
* 适合所有类型的序列进行排序
* 既可以升序排序，也可以降序排序
*/
int main(void)
{
	test1();
	test2();
	test3();
	test4();

	return 0;
}

